/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pacoteAnalisadorSintatico;

import java.util.ArrayList;
import pacoteAutomato.Token;

/**
 *
 * @author Isabela
 */
public class SintaticoGeral {

    ArrayList<Token> tokensRecebidos;
    ErroSintatico erroSint;

    boolean matchTipo(String esperado, Token recebido) {
        if (esperado.equalsIgnoreCase(recebido.getTipo())) {
            return true;
        } else {
            return false;
        }
    }

    boolean matchLexema(String esperado, Token recebido) {
        if (esperado.equalsIgnoreCase(recebido.getLexema())) {
            return true;
        } else {
            return false;
        }
    }

    public ErroSintatico program() {

        if (matchLexema("algoritmo", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            if (matchTipo("IDENT", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                while (true) {
                    if (matchLexema("variaveis", tokensRecebidos.get(0))) {
                        erroSint = dec_Variaveis();
                        if (erroSint != null) {
                            return erroSint;
                        }
                    } else if (matchLexema("tipo", tokensRecebidos.get(0))) {
                        erroSint = tipoCriadoUsuario();
                        if (erroSint != null) {
                            return erroSint;
                        }
                    } else if (matchLexema("registro", tokensRecebidos.get(0))) {
                        erroSint = tipoCriadoUsuario();
                        if (erroSint != null) {
                            return erroSint;
                        }
                    } else {
                        break;
                    }
                }
                while (true) {
                    if (matchLexema("funcao", tokensRecebidos.get(0))) {
                        erroSint = funcao();
                        if (erroSint != null) {
                            return erroSint;
                        }
                    } else {
                        break;
                    }
                }
                erroSint = principal();
                if (erroSint != null) {
                    return erroSint;
                }
            } else {
                return erroSint = new ErroSintatico("Identificador", tokensRecebidos.get(0));
            }
        } else {
            return erroSint = new ErroSintatico("algoritmos", tokensRecebidos.get(0));
        }

        return null;
    }

    public ErroSintatico funcao() {
        if (matchLexema("funcao", tokensRecebidos.get(0))) { //palavra funcao é representativa. Tem q checar se é conjunto primeiro de funcao
            tokensRecebidos.remove(0);
            return null;
        } else {
            return new ErroSintatico("funcao", tokensRecebidos.get(0));
        }
    }

    public ErroSintatico principal() {

        if (matchLexema("vazio", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            if (matchLexema("principal", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                if (matchLexema("(", tokensRecebidos.get(0))) {
                    tokensRecebidos.remove(0);
                    if (matchLexema(")", tokensRecebidos.get(0))) {
                        tokensRecebidos.remove(0);
                        if (matchLexema("{", tokensRecebidos.get(0))) {
                            tokensRecebidos.remove(0);
                            while (true) {
                                if (matchLexema("Comando", tokensRecebidos.get(0))) //elementos do conjunto primeiro de comando
                                {
                                    ErroSintatico erro = new ErroSintatico();
                                    erro = comando();
                                    if (erro != null) {
                                        return erro;
                                    }
                                } else {
                                    break;
                                }
                            }
                            if (matchLexema("retorno", tokensRecebidos.get(0))) {
                                tokensRecebidos.remove(0);
                                if (matchLexema("vazio", tokensRecebidos.get(0))) {
                                    tokensRecebidos.remove(0);
                                    if (matchLexema(";", tokensRecebidos.get(0))) {
                                        tokensRecebidos.remove(0);
                                        if (matchLexema("}", tokensRecebidos.get(0))) {
                                            tokensRecebidos.remove(0);
                                        } else {
                                            return new ErroSintatico("}", tokensRecebidos.get(0));
                                        }
                                    } else {
                                        return new ErroSintatico(";", tokensRecebidos.get(0));
                                    }
                                } else {
                                    return new ErroSintatico("vazio", tokensRecebidos.get(0));
                                }
                            } else {
                                return new ErroSintatico("retorno", tokensRecebidos.get(0));
                            }
                        } else {
                            return new ErroSintatico("{", tokensRecebidos.get(0));
                        }
                    } else {
                        return new ErroSintatico(")", tokensRecebidos.get(0));
                    }
                } else {
                    return new ErroSintatico("(", tokensRecebidos.get(0));
                }
            } else {
                return new ErroSintatico("principal", tokensRecebidos.get(0));
            }
        } else {
            return new ErroSintatico("vazio", tokensRecebidos.get(0));
        }
        return null;
    } //tá feito

    public ErroSintatico comando() {
        if (matchLexema("Comando", tokensRecebidos.get(0))) { //aqui comando checaria o first dele e setaria a var em true ou false dependendo disso
            tokensRecebidos.remove(0);
            return null;                               //né q vai ser comando ali n, é q tem q pegar o first dele
        } else {
            return new ErroSintatico("Comando", tokensRecebidos.get(0));
        }
    }

    //'variaveis' (tipos_primitivos|IDENT) IDENT((('='expressoes)?)| declaracao_vetor)';'
    public ErroSintatico dec_Variaveis() {
        ErroSintatico erro = new ErroSintatico();
        if (matchLexema("variaveis", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            if (checaPrimitivosIdent()) {
                if (matchTipo("IDENT", tokensRecebidos.get(0))) {
                    tokensRecebidos.remove(0);
                    if (matchLexema(";", tokensRecebidos.get(0))) {
                        tokensRecebidos.remove(0);
                        return null;
                    } else if (matchLexema("=", tokensRecebidos.get(0))) {
                        tokensRecebidos.remove(0);

                        erro = expressoes(); //aqui o cidadão bota a regra de expressões
                        if (erro == null) {
                            if (matchLexema(";", tokensRecebidos.get(0))) {
                                tokensRecebidos.remove(0);
                            } else {
                                return new ErroSintatico(";", tokensRecebidos.get(0));
                            }
                        } else {
                            return new ErroSintatico("'verdadeiro', 'falso', '(', Identificador, Inteiro, ou '++'", tokensRecebidos.get(0));
                        }
                    } else if (matchLexema("[", tokensRecebidos.get(0))) {
                        //erro = dec_vetor(); aqui o cidadão bota a regra de criar vetor
                        if (erro == null) {
                            if (matchLexema(";", tokensRecebidos.get(0))) {
                                tokensRecebidos.remove(0);
                            } else {
                                return new ErroSintatico(";", tokensRecebidos.get(0));
                            }
                        } else {
                            return new ErroSintatico("'verdadeiro', 'falso', '(', Identificador, Inteiro, ou '++'", tokensRecebidos.get(0));
                        }
                    } else {
                        return new ErroSintatico("'=', ';' ou '['", tokensRecebidos.get(0));
                    }
                } else {
                    return new ErroSintatico("Identificador", tokensRecebidos.get(0));
                }
            } else {
                return new ErroSintatico("Identificador, 'inteiro', 'real', 'lógico', 'caracter' ou 'String'", tokensRecebidos.get(0));
            }
        } else {
            return new ErroSintatico("variaveis", tokensRecebidos.get(0));
        }
        return null;
    }

    public ErroSintatico parametrosAtual() {
        ErroSintatico erro = new ErroSintatico();
        erro = expressoes();
        if (erro == null) {
            if (matchLexema(",", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                while (true) {
                    if (matchLexema("expressoes", null)) {
                        erro = expressoes();
                    }
                    if (erro != null) {
                        return erro;
                    }
                }
            }
        } else {
            return erro;
        }
        return null;
    }

    public ErroSintatico parametros() {
        ErroSintatico erro = new ErroSintatico();
        erro = parametro();
        if(erro == null){
         if (matchLexema(",", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                while (true) {
                    if (matchLexema("parametro", null)) {
                        erro = parametro();
                    }
                    if (erro != null) {
                        return erro;
                    }
                }
        }
        }
       else {
            return erro;
        }
         return null;
    }

     public ErroSintatico tipos_primitivos() {
        if (matchLexema("inteiro", tokensRecebidos.get(0))
                || matchLexema("real", tokensRecebidos.get(0))
                || matchLexema("logico", tokensRecebidos.get(0))
                || matchLexema("caractere", tokensRecebidos.get(0))
                || matchLexema("String", tokensRecebidos.get(0))
                ) {
            tokensRecebidos.remove(0);
        } else {
            return new ErroSintatico("inteiro || real || logico || caractere || string", tokensRecebidos.get(0));
        }
        return null;
    }

//Não terminado
     public ErroSintatico declaracao_vetor(){
      if (matchLexema("[", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            if (matchTipo("INTEGER", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
               if (matchTipo("]", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
            

      }else {
            return new ErroSintatico("Dec Vetor", tokensRecebidos.get(0));
        }
        
     }
      }
      return null;
     }

    public ErroSintatico tipoRegistro() {
        if (matchLexema("registro", tokensRecebidos.get(0))) { //aqui fica a estrutura do registro inteira
            tokensRecebidos.remove(0);
            return null;
        } else {
            return new ErroSintatico("registro", tokensRecebidos.get(0));
        }
    }

    public ErroSintatico tipoCriadoUsuario() {
        if (matchLexema("tipo", tokensRecebidos.get(0))) { //aqui fica a estrutura do criado inteira
            tokensRecebidos.remove(0);
            return null;
        } else {
            return new ErroSintatico("registro", tokensRecebidos.get(0));
        }

    }

    public ErroSintatico comando_leia() {

        if (matchLexema("leia", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            if (matchTipo("IDENT", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                if (matchLexema(";", tokensRecebidos.get(0))) {
                    tokensRecebidos.remove(0);
                } else {
                    return new ErroSintatico(";", tokensRecebidos.get(0));
                }
            } else {
                return new ErroSintatico("IDENT", tokensRecebidos.get(0));
            }
        } else {
            return new ErroSintatico("leia", tokensRecebidos.get(0));
        }
        return null;
    }

    public ErroSintatico parametro() {

        if (checaPrimitivosIdent()) {
            if (matchTipo("IDENT", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
                if (matchLexema("[", tokensRecebidos.get(0))) {
                    tokensRecebidos.remove(0);
                    if (matchLexema("]", tokensRecebidos.get(0))) {
                        tokensRecebidos.remove(0);
                    } else {
                        return new ErroSintatico("]", tokensRecebidos.get(0));
                    }
                } else {
                    return new ErroSintatico("[", tokensRecebidos.get(0));
                }
            } else {
                return new ErroSintatico("IDENT", tokensRecebidos.get(0));
            }
        } else {
            return new ErroSintatico("Identificador, 'inteiro', 'real', 'lógico', 'caracter' ou 'String'", tokensRecebidos.get(0));
        }

        return null;
    }

    //só getters e setters
    public ArrayList<Token> getTokensRecebidos() {
        return tokensRecebidos;
    }

    public void setTokensRecebidos(ArrayList<Token> tokensRecebidos) {
        this.tokensRecebidos = tokensRecebidos;
    }

    public ErroSintatico getErroSint() {
        return erroSint;
    }

    //métodos auxiliares
    public boolean checaPrimitivosIdent() {
        if (matchLexema("inteiro", tokensRecebidos.get(0)) || matchLexema("character", tokensRecebidos.get(0)) || matchLexema("real", tokensRecebidos.get(0)) || matchLexema("logico", tokensRecebidos.get(0)) || matchLexema("String", tokensRecebidos.get(0)) || matchTipo("IDENT", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
            return true;
        } else {
            return false;
        }
    }

    public ErroSintatico expressoes() {
        return expressao_logica();

    }

    public ErroSintatico expressao_logica() {
        ErroSintatico erro = null;

        if (matchLexema("verdadeiro", tokensRecebidos.get(0)) || matchLexema("falso", tokensRecebidos.get(0))) {
            erro = expressao_booleana();
            if (erro != null) {
                return erro;
            }
        } else if (matchLexema("(", tokensRecebidos.get(0)) || matchLexema("IDENT", tokensRecebidos.get(0)) || matchLexema("INTEGER", tokensRecebidos.get(0)) || matchLexema("++", tokensRecebidos.get(0)) || matchLexema("--", tokensRecebidos.get(0))) {
            erro = expressao_relacional();
            if (erro != null) {
                return erro;
            }
        }
        while (true) {
            if (matchLexema("&&", tokensRecebidos.get(0)) || matchLexema("||", tokensRecebidos.get(0))) {
                tokensRecebidos.remove(0);
            } else {
                break;
            }

            if (matchLexema("verdadeiro", tokensRecebidos.get(0)) || matchLexema("falso", tokensRecebidos.get(0))) {
                erro = expressao_booleana();
                if (erro != null) {
                    return erro;
                }
            } else if (matchLexema("(", tokensRecebidos.get(0)) || matchLexema("IDENT", tokensRecebidos.get(0)) || matchLexema("INTEGER", tokensRecebidos.get(0)) || matchLexema("++", tokensRecebidos.get(0)) || matchLexema("--", tokensRecebidos.get(0))) {
                erro = expressao_relacional();
                if (erro != null) {
                    return erro;
                }
            }
        }
        return null;




    }

    public ErroSintatico expressao_booleana() {
        if (matchLexema("verdadeiro", tokensRecebidos.get(0)) || matchLexema("falso", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
        } else {
            return new ErroSintatico("verdadeiro||falso", tokensRecebidos.get(0));
        }
        return null;
    }

    public ErroSintatico expressao_relacional() {   ///não acabei--> só começei!!
        if (matchLexema("verdadeiro", tokensRecebidos.get(0)) || matchLexema("falso", tokensRecebidos.get(0))) {
            tokensRecebidos.remove(0);
        } else {
            return new ErroSintatico("verdadeiro||falso", tokensRecebidos.get(0));
        }
        return null;
    }
}
